以下知識全部取自張元,如果需要,最下面reference有給影片連結
當我們在寫C/C++程式時,每當一個函式被呼叫,作業系統會分配一個暫時的記憶體區塊來儲存該函式的區域變數、回傳位址等等,這個區塊就稱為 stack frame,那由於我們之後也要探討buffer overflow的漏洞利用,所以也需要先了解stack frame的內容才可以清楚理解buf的細節
stack frame重要的兩個步驟
一個function的stack frame差不多就像下面那樣子,以下是我參考張元做的stack frame表:
那我們現在來看function prologue跟function epilogue的流程
rip現在是停在call function的部分,被指到代表即將執行這一行,但是還沒執行這一行
func:
push rbp
mov rbp, rsp
sub rsp, 0x70
...
mov eax, 0x1
leave
ret
main:
push rbp
mov rbp, rsp
mov rdi, 1234
mov rsi, 666
call func <== rip
mov eax, 0 // address = 0x40071A
leave
ret
call function這個instruction可以看做是
push next-rip
jmp func
他會把next-rip push到stack
這樣就可以jump到func
func:
push rbp <== rip
mov rbp, rsp
sub rsp, 0x70
...
mov eax, 0x1
leave
ret
main:
push rbp
mov rbp, rsp
mov rdi, 1234
mov rsi, 666
call func
mov eax, 0 // address = 0x40071A
leave
ret
其實可以發現,compiler在前面三行都是,這個其實就是function prologue的部分
push rbp ; 保存舊的 base pointer
mov rbp, rsp ; 設定新的 base pointer
sub rsp, N ; 預留區域變數空間(N 是需要的大小,指區域變數)
接下來就會執行compiler幫我們加的function prologue的instruction
func:
push rbp
mov rbp, rsp <== rip
sub rsp, 0x70
...
mov eax, 0x1
leave
ret
main:
push rbp
mov rbp, rsp
mov rdi, 1234
mov rsi, 666
call func
mov eax, 0 // address = 0x40071A
leave
ret
然後就會執行mov rbp, rsp
,這樣就會讓rbp指向跟rsp一樣的位址
再來就會執行sub rsp, 0x70
0x70這個值是compiler在compile的時候就已經決定好了
func:
push rbp
mov rbp, rsp
sub rsp, 0x70 <== rip
...
mov eax, 0x1
leave
ret
main:
push rbp
mov rbp, rsp
mov rdi, 1234
mov rsi, 666
call func
mov eax, 0 // address = 0x40071A
leave
ret
那就會挪出0x70的位置給local variable
那我們可以發現我們的rsp跟rbp都已經指向function的stack frame上了
這樣我們就完成我們的function prologue了 uwu
然後我們離開後執行mov eax, 0x1
把return value放rax暫存器後
我們就會執行leave ret,那這也是function epilogue的環節
func:
push rbp
mov rbp, rsp
sub rsp, 0x70
...
mov eax, 0x1
leave <== rip
ret
main:
push rbp
mov rbp, rsp
mov rdi, 1234
mov rsi, 666
call func
mov eax, 0 // address = 0x40071A
leave
ret
mov rsp, rbp
pop rbp
所以rsp也會指到rbp的地方
pop rbp
,那pop rbp
就是把rsp現在指的地方的值塞到rbp接下來我們執行ret
func:
push rbp
mov rbp, rsp
sub rsp, 0x70
...
mov eax, 0x1
leave
ret <== rip
main:
push rbp
mov rbp, rsp
mov rdi, 1234
mov rsi, 666
call func
mov eax, 0 // address = 0x40071A
leave
ret
pop rip
那這時候我們function epilogue就結束了
func:
push rbp
mov rbp, rsp
sub rsp, 0x70
...
mov eax, 0x1
leave
ret
main:
push rbp
mov rbp, rsp
mov rdi, 1234
mov rsi, 666
call func
mov eax, 0 // address = 0x40071A <== rip
leave
ret
以上就是stack frame的運作以及function prologue跟function epilogue的流程
那我們理解完這些知識後,明天就要接觸buffer overflow了w今天寫這個筆記快累死,明天應該可以輕鬆一點
明天見~~
https://www.youtube.com/watch?v=U8N6aE-Nq-Q&t=2303s